;; === PARSER ==

(deflexer lexer
          ("0x[0-9A-Fa-f]+" (return (values 'int (parse-integer (subseq %0 6) :radix 16)))) ;; only the last 4 hexdigits are used (0-65535)
          ("[0-9]+([.][0-9]+([Ee][0-9]+)?)" (return (values 'flt (num %0))))
          ("[0-9]+" (return (values 'int (int %0))))
          ("[:alpha:]+[:alnum:]*" (return (values 'name %0)))
          ("[{]" (return (values 'lbracket)))
          ("[}]" (return (values 'rbracket)))
          ("//.*\\n")
          ("[:space:]+") )

(define-parser *libsl-parser*
               (:start-symbol config-file)
               (:terminals (int flt name lbracket rbracket))
               (config-file (version-number packets #'(lambda (a b) b)))
               (version-number (name flt))
               (packets
                 (packet packets #'(lambda (a b) (cons a b)))
                 (packet))
               (packet 
                 (lbracket packet-header packet-blocks rbracket #'(lambda (a b c d) (append b (list c))))
                 (lbracket packet-header rbracket #'(lambda (a b c) b)))
               (packet-header
                 (name name int name name #'(lambda (a b c d e)  (list a (intern b :libsl) c d e nil))) ;; TestMessage Low 1 NotTrusted Zerocoded
                 (name name int name name name #'(lambda (a b c d e f)  (list a (intern b :libsl) c d e f))))
               (packet-blocks
                 (packet-block packet-blocks #'(lambda (a b) (cons a b)))
                 (packet-block))
               (packet-block (lbracket block-name variables rbracket #'(lambda (a b c d) (append b (list c)))))
               (block-name 
                  (name name #'(lambda (a b) (list a (intern b :libsl) 0))) ;;  NeighborBlock Single
                  (name name int #'(lambda (a b c) (list a (intern b :libsl) c)))) ;;  NeighborBlock Multiple 4
               (variables
                 (variable variables #'(lambda (a b) (cons a b)))
                 (variable))
               (variable 
                 (lbracket name name rbracket #'(lambda (a b c d)(list b (intern c :libsl)))) ;; ID U32
                 (lbracket name name int rbracket #'(lambda (a b c d e)(list b (intern c :libsl) d)))))

;; === PARSE TREE UTILITY FUNCTIONS ==

(defun parse (parser token-stream)
    (parse-with-lexer token-stream parser))


(defun packet-name (packet) (first packet))
(defun packet-header-type (packet) (if (eq '|Fixed| (second packet)) '|Low| (second packet)))
(defun packet-number (packet) (third packet))
(defun packet-status (packet) (fourth packet))
(defun packet-zerocoded? (packet) (string= "Zerocoded" (fifth packet)))
(defun packet-something (packet) (sixth packet)) ;; TODO: find out what this is
(defun packet-blocks (packet) (seventh packet))
(defun packet-header-size (packet) 
  (ecase (packet-header-type packet)
    (|Low| 10)
    (|Medium| 8)
    (|High| 7)))

(defun block-name (block) (first block))
(defun block-type (block) (second block))
(defun block-cardinality (block) (third block))
(defun block-vars (block) (fourth block))

(defun var-size (var-data)
  "Return the size of the variable type in bytes"
  (ecase (var-type var-data)
    (|BOOL| 1)
    (|Fixed| (var-type-arg var-data))
    (|U16| 2)
    (|S16| 2)
    (|U64| 8)
    (|LLVector3| 12)
    (|LLVector4| 16)
    (|LLVector3d| 24)
    (|LLQuaternion| 12)
    (|LLUUID| 16)
    (|IPADDR| 4)
    (|IPPORT| 2)
    (|F32| 4)
    (|F64| 8)
    (|S8| 1)
    (|S32| 4)
    (|U8| 1)
    (|U32| 4)))

(defun var-name (var-data) (first var-data))
(defun var-type (var-data) (second var-data))
(defun var-type-arg (var-data) (third var-data))

